﻿using System;
using System.Web;
using System.Web.Caching;

namespace Netkk.Common
{
    /// <summary>
    /// Encapsulates the possibilities of <see cref="HttpRuntime.Cache" />
    /// within static methods with overloads.
    /// </summary>
    public static class CacheWrapper
    {
        /// <summary>
        /// Removes a specific entry from cache.
        /// </summary>
        /// <param name="cacheKey">Cache key</param>
        public static void Invalidate(string cacheKey)
        {
            HttpRuntime.Cache.Remove(cacheKey);
        }

        /// <summary>
        /// Loads an entry from cache without dependency.
        /// </summary>
        /// <typeparam name="T">The type from the object to load.</typeparam>
        /// <param name="cacheKey">The cache key</param>
        /// <param name="loadMethod">The method to load the data.</param>
        /// <returns></returns>
        public static T Load<T>(string cacheKey, Func<T> loadMethod) where T : class
        {
            return Load(cacheKey, data => HttpRuntime.Cache[cacheKey] = data, loadMethod);
        }

        /// <summary>
        /// Loads an entry from the cache with a absolute expiration span.
        /// </summary>
        /// <typeparam name="T">The type from the object to load.</typeparam>
        /// <param name="cacheKey">The cache key</param>
        /// <param name="absoluteExpirationSpan">The absolute expiration span.</param>
        /// <param name="loadMethod">The method to load the data.</param>
        /// <returns></returns>
        public static T Load<T>(string cacheKey, TimeSpan absoluteExpirationSpan, Func<T> loadMethod) where T : class
        {
            return Load(cacheKey,
                                (data) => HttpRuntime.Cache.Insert(cacheKey,
                                                                   data,
                                                                   null,
                                                                   DateTime.UtcNow.Add(absoluteExpirationSpan),
                                                                   Cache.NoSlidingExpiration),
                                 loadMethod);
        }

        /// <summary>
        /// Loads an entry from cache and associate it with a cache dependency.
        /// </summary>
        /// <typeparam name="T">The type from the object to load.</typeparam>
        /// <param name="cacheKey">The cache key</param>
        /// <param name="dependency">The cache dependency.</param>
        /// <param name="loadMethod">The method to load the data.</param>
        /// <returns></returns>
        public static T Load<T>(string cacheKey, CacheDependency dependency, Func<T> loadMethod) where T : class
        {
            return Load(cacheKey,
                                 (data) => HttpRuntime.Cache.Insert(cacheKey,
                                                                    data,
                                                                    dependency), loadMethod);
        }

        /// <summary>
        /// Loads an entry from cache.
        /// Encapsulates the cache pattern.
        /// </summary>
        /// <typeparam name="T">The type from the object to load.</typeparam>
        /// <param name="cacheKey">The cache key</param>
        /// <param name="insertMethod">The method to insert the data.</param>
        /// <param name="loadMethod">The method to load the data.</param>
        /// <returns></returns>
        public static T Load<T>(string cacheKey,
                                         Action<T> insertMethod,
                                         Func<T> loadMethod) where T : class
        {
            T data = HttpRuntime.Cache[cacheKey] as T;
            if (data == null)
            {
                data = loadMethod();
                insertMethod(data);
            }
            return data;
        }
    }
}